#!/bin/bash
##############################################################################
# This script is used to monitor a PPTP VPN connection. The script will do   #
# the follow things:                                                         #
#   1) Verify the presence of a ppp interface known to the OS.               #
#   2) Should that apapter exist, the script will then attempt to ping an IP #
#      of your choosing in the destination network to verify that traffic is #
#      is passing over the tunnel properly.                                  #
#   3) If the tunnel is not functioning properly, the script will notify the #
#      admin via syslog entries and push notifications via pushover.net      #
#   4) Following the notifications, the script will attempt to reconnect.    #
##############################################################################
# The following variables must be filled in for the script to function       #
##############################################################################
# The name of the config file to run with the "pon" and "poff" commands.
tunnelname="tunnelnamehere"
# The ip address of the host you wish to monitor traffic passing against.
# (this host must respond to ping requests susscessfully)
pinghost="111.222.333.444"
# Your pushover.net API token and user name to be passed while sending iPhone
# notifications. Instructions for this are at: https://pushover.net/api
pushoverapitoken="BigLongStringOfCharacters"
pushoverapiuser="MoreBigLongStrings"
# The following variable represents how many times the VPN test script thinks
# the tunnel is down before sending you repeat notifications. It will always
# notify you via iPhone the first time it thinks the tunnel is down, and it
# will always write it's progress to the syslog. The test loop runs once per
# minute when the tunnel is down, so the number below represents how many
# minutes you will go between getting iPhone notifications about the tunnel
# still being down. The default here is 60, which means you will be notified
# the first time the tunnel is down, then once each hour until it comes back.
notificationinterval="60"
# The hostname variable is the text that will be sent in both syslog and
# iPhone notifications to identify which server is generating the error.
hostname="hostname.domain.tld"
##############################################################################
#                    MAKE NO CHANGES BELOW THIS LINE                         #
##############################################################################

#Tell syslog we're starting the script to check VPN status
logger -t VPNCHECK "NA: SCRIPT BEGINS"

#Set the counter and interval counter to 1 signifying the first check
counter=1
intervalcounter=1

# The follow variable is used to track the current state of the VPN.
# This is used to lessen the number of "down" notifications that go
# out, as well as to be able to provide a notification that the VPN
# is back up. It's initial state is -1 signifying that the VPN status
# has never been checked.
vpnworking=-1

# VPN Status text
vpnstatus=NA

#if the counter is less than 10001, keep checking
while [ $counter -lt 10001 ]; do
# The following variables track the state of the VPN connection.
# 'pingcount' is used to keep track of how many pings can NOT
# reach the default gateway of the LAN and the 'totppptuns'
# variable keeps a count of how many pptp tunnels are registered
# as interfaces on this server.
pingcount=-1
totppptuns=-1

# The folling line checks the number of "ppp" interfaces are reported
# by the "ifconfig" command.
totppptuns=$(ifconfig | grep ppp -c)

# The following sections are used to test tunnel traffic passing.
# If the 'totppptuns' variable reports that the pptp vpn tunnel is
# in fact up, the 'pingcount' variable is used to verify the tunnel
# is passing traffic properly to the default gateway of the LAN.
if [ $totppptuns -gt 0 ]; then
    logger -t VPNCHECK $vpnstatus": Loop "$counter", PPTP tunnel interface is present, confirm traffic passing."

    # The follow line attempts to ping the default gateway of the LAN
    # which is only reachable if the tunnel is up and still passing
    # traffic appropriately. The number of MISSED pings is recorded to
    # be used later.
    pingcount=$(ping $pinghost -c 10 | grep "Unreachable" -c)

    # The follow if statement takes the number of missed pings and determines
    # if they are missed due to packet loss, or a faulty tunnel entirely. If 4
    # or more pings have been missed, the script considers the VPN tunnel down.
    if [ $pingcount -lt 4 ]; then
        vpnstatus=UP
        #tell the syslog we're up
        logger -t VPNCHECK $vpnstatus": Loop "$counter", Tunnel is passing traffic, missing ping count is: "$pingcount

        #reset the "down interval counter"
        let intervalcounter=1

        #if the vpn was previously down, tell us it's up!
        if [ $vpnworking -eq 0 ]; then
            #reset the vpn status to functional
            vpnworking=1

            #tell the syslog we're notifying the iphone:
            logger -t VPNCHECK $vpnstatus": Loop "$counter", Notifying the iPhones"

            #tell my iphone we're back up
            pushoverstatus=$(curl -s \
              -F "token=$pushoverapitoken" \
              -F "user=$pushoverapiuser" \
              -F "message=VPN tunnel on $hostname is now passing traffic. Pingcount: "$pingcount \
                https://api.pushover.net/1/messages.json)

           #output the pushover status to the syslog
           logger -t VPNCHECK $vpnstatus": Loop "$counter", Pushover.net notification status: "$pushoverstatus "(1)"
        fi
        
        #to be safe, set the vpn working:
        vpnworking=1

        #since we're up, don't check as frequently. Pause for 5 minutes (300 seconds).
        sleep 300
    fi

    # This test uses the same variable as above, however if anything more
    # than 3 missed pings occur, the script things the tunnel is down, attempts
    # to reconnect and notifies the syslog as well as my iPhone.
    if [ $pingcount -gt 3 ]; then
        vpnstatus=DOWN
        #tell the syslog we're down
        logger -t VPNCHECK $vpnstatus": Loop "$counter", Tunnel is NOT passing traffic, missing ping count is: "$pingcount

        #set the current state of the vpn to down
        vpnworking=0

        if [ $intervalcounter -eq 1 ]; then
            #tell the syslog we're notifying the iphone:
            logger -t VPNCHECK $vpnstatus": Loop "$counter", Notifying the iPhones"

            #use pushover.net to tell my iPhone we're down
            pushoverstatus=$(curl -s \
               -F "token=$pushoverapitoken" \
               -F "user=$pushoverapiuser" \
               -F "message=VPN is DOWN on $hostname due to missed pings. Pingcount: "$pingcount \
               https://api.pushover.net/1/messages.json)

            #output the pushover status to the syslog
            logger -t VPNCHECK $vpnstatus": Loop "$counter", Pushover.net notification status: "$pushoverstatus "(2)"
        fi

        #increment the interval counter after reporting the VPN is down.
        let intervalcounter=$intervalcounter+1

        #Tell the syslog we're attempting a reconnect
        logger -t VPNCHECK $vpnstatus": Loop "$counter", Attemping to disconnect, then reconnect VPN"

        #run pptp disconnect, then reconnect command to the specified tunnel
        /usr/bin/poff $tunnelname
        sleep 2
        /usr/bin/pon $tunnelname

        #pause checking for 60 seconds
        sleep 60
    fi
fi

# The following section runs when the ppp interface is NOT found!
if [ $totppptuns -lt 1 ]; then
    #change the status of the vpn to '0' showing that it's down.
    vpnworking=0
    #wet the vpnstatus text for systlogging
    vpnstatus=DOWN
    #tell the syslog we're down
    logger -t VPNCHECK $vpnstatus": Loop "$counter", PPTP tunnel interface is NOT present! Notifying and reconnecting."

    if [ $intervalcounter -eq 1 ]; then
        #tell the syslog we're notifying the iphone:
        logger -t VPNCHECK $vpnstatus": Loop "$counter", Notifying the iPhones"

        #use pushover.net to tell my iPhone we're down and capture the output from the API call.
        pushoverstatus=$(curl -s \
          -F "token=$pushoverapitoken" \
          -F "user=$pushoverapiuser" \
          -F "message=VPN is DOWN on $hostname! Pingcount: "$pingcount \
          https://api.pushover.net/1/messages.json)

        #output the pushover status to the syslog
        logger -t VPNCHECK $vpnstatus": Loop "$counter", Pushover.net notification status: "$pushoverstatus "(3)"
    fi

    #increment the interval counter after reporting the VPN is down.
    let intervalcounter=$intervalcounter+1

    #run pptp connect command to specified tunnel
    /usr/bin/pon $tunnelname

    #pause checking for 60 seconds
    sleep 60
fi

# Test to see if we should reset the interval counter.
if [ $intervalcounter -gt $notificationinterval ]; then
    let intervalcounter=1
fi


# Increment the counter
let counter=$counter+1

#mark the end of the look, code starts here after the counter has run out.
done

#tell the syslog the script to check VPN status has ended
logger -t VPNCHECK $vpnstatus": Loop "$counter", SCRIPT ENDS"
